/**
 * @author WY
 * @since 2024/03
 */

import { ParameterObjectType, SketchFrame } from '@amcax/base';
import { ctx2, userEvents } from '@app-cad/module';
import { Vector3, Object3D } from 'three-legacy';
import { DimCallback } from '../types';
import { DivMesh } from './divMesh';
import { DimLabel, DimLabelProps } from './DimLabel';
import { CSS2DReactObject } from '@app-base/common/components/css-2d-react-object/CSS2DReactObject';
import { DIM_EVENTS } from '@app-base/common/Constants';

export type DimCss2dInputLableAttrs = {
  position: Vector3; // 位置
  text: number; // 数值
  textParam?: string; // 数值对应的公式，可能没有
  multiple?: number; // 类型
  id?: string | number; // 对应的id
  onfocus?: boolean; // 是否处于激活状态
  inputType?: ParameterObjectType;
  prefix?: string; // 符号
  sketchFrame?: SketchFrame;
  allowExpression?: boolean; // 是否允许输入公式
  callback?: DimCallback; //
};
export class DimCss2dInputLable {
  object: CSS2DReactObject<DimLabelProps>; // css2dObject对象
  isActive: boolean = false; // 是否处于激活状态
  allowExpression?: boolean; // 是否允许输入公式
  text: number; // 最终数值内容
  textParam?: string; // 数值对应的公式，可能没有
  scene: Object3D; // 场景对象
  prefix: string = ''; // 前缀
  inputType: ParameterObjectType;
  type: string; // 类型
  multiple: number = 1; // 乘数
  divHtml: HTMLDivElement;
  divMesh: DivMesh;
  sketchFrame: SketchFrame;
  dimId: string | number;

  callback: DimCallback;
  constructor(attrs?: DimCss2dInputLableAttrs) {
    this.init(attrs);
  }

  updateDimLabelProps(props: Partial<DimLabelProps>) {
    this.object.updateProps({
      ...this.object.props,
      ...props,
    });
  }

  setDisable(isDisable: boolean) {
    this.updateDimLabelProps({
      disabled: isDisable,
      isEdit: false,
    });
  }
  getType() {
    return 'css2dInputLable';
  }

  setHover(hovered: boolean) {
    this.updateDimLabelProps({
      hovered,
    });
  }

  setSelected(selected: boolean) {
    if (selected === this.object.props.selected) {
      return;
    }

    this.updateDimLabelProps({
      selected,
      isEdit: false,
    });
  }

  init(attrs?: DimCss2dInputLableAttrs) {
    if (attrs.sketchFrame) {
      this.sketchFrame = attrs.sketchFrame;
    }
    this.multiple = attrs.multiple || 1; // 单位倍数
    this.prefix = attrs.prefix || ''; // 前置标记
    this.dimId = attrs.id || ''; // 标注id
    this.callback = attrs.callback; // 回调函数
    this.isActive = attrs.onfocus || false; // 是否获取焦点
    this.inputType = attrs.inputType ?? ParameterObjectType.Real;
    this.text = Math.abs(attrs.text || 0);
    this.textParam = attrs.textParam;
    this.allowExpression = attrs.allowExpression;
    // 标注的位置
    const pos = this.sketchFrame.toWorld(attrs.position);
    this.createCss2DObject(pos); // 创建css2d对象
    this.updateText(this.text); // 设置文本
    this.updateParam(this.textParam);
    if (this.sketchFrame) {
      this.createMesh();
    }
  }
  private updateText(text: number) {
    this.updateDimLabelProps({
      value: text,
    });
  }

  private updateParam(param: string) {
    this.updateDimLabelProps({
      param,
    });
  }

  private createCss2DObject(pos: Vector3) {
    this.divHtml = document.createElement('div');
    if (this.dimId) {
      this.divHtml.id = `${'divHtml'}_${this.dimId}`;
    }

    this.object = new CSS2DReactObject<DimLabelProps>(this.divHtml, DimLabel, {
      type: this.inputType,
      prefix: this.prefix,
      disabled: false,
      isEdit: false,
      value: 0,
      allowActive: true,
      hovered: false,
      selected: false,
      param: this.textParam,
      allowExpression: this.allowExpression,
      onChange: async (active, text, textParam) => {
        if (text != null) {
          this.text = text;
          this.textParam = textParam;
        }

        if (!active && text != null && this.isActive) {
          this.callback?.('blur', this.text, null, this.textParam ?? '');
        } else {
          this.callback?.(active ? 'focus' : 'blur');
        }

        this.isActive = active;

        this.updateDimLabelProps({
          isEdit: active,
        });
      },
      multiple: this.multiple,
    });

    this.object.position.set(pos.x, pos.y, pos.z);
    this.object.name = 'css2dInputLable';
  }
  private createMesh() {
    setTimeout(() => {
      this.divMesh = new DivMesh({
        id: this.dimId.toString(),
        sketchFrame: this.sketchFrame,
        widthHeight: this.getLabelWH(),
        position: this.object.position,
      });
      if (this.scene) {
        this.divMesh.addTo(this.scene);
      }
      this.divMesh?.setVisible(false);
    }, 500);
  }
  private updateMesh() {
    if (this.divMesh) {
      // 设置尺寸标签的初始位置
      this.divMesh.update({
        position: this.object.position,
        widthHeight: this.getLabelWH(),
      });
    }
  }
  getLabelWH() {
    return {
      width: this.divHtml.offsetWidth,
      height: this.divHtml.offsetHeight,
    };
  }

  update({
    prefix,
    text,
    pos,
    callback,
    param,
  }: {
    prefix?: string;
    text?: number;
    pos?: Vector3;
    callback?: DimCallback;
    param?: string;
  }) {
    this.prefix = prefix ?? this.prefix;
    if (text || text === 0) {
      this.text = text;
      this.updateText(Math.abs(text));
    }
    if (param != null) {
      this.textParam = param;
      this.updateParam(param);
    }
    if (callback) {
      this.callback = callback;
    }
    if (pos) {
      const p = this.sketchFrame.toWorld(pos);
      this.object.position.set(p.x, p.y, p.z);
    }
    this.updateMesh();
  }
  // 设置激活
  focus() {
    if (!this.isActive) {
      // 使用事件，规避循环引用
      userEvents.emit(DIM_EVENTS.DIM_CSS_2D_INPUT_FOCUS);
      this.isActive = true; // 设置激活状态
      ctx2.viewer.requestRender();

      this.updateDimLabelProps({
        isEdit: true,
      });
    }
  }

  // 设置失焦
  blur() {
    this.updateDimLabelProps({
      isEdit: false,
    });
  }
  // 允许click激活
  clickFocus() {
    this.updateDimLabelProps({
      allowActive: true,
    });
  }
  // 不允许click激活
  unClickFocus() {
    this.updateDimLabelProps({
      allowActive: false,
    });
  }
  // 获取当前数值
  getText() {
    return this.text;
  }

  // 销毁当前对象
  destroy() {
    this.scene?.remove(this.object);
  }
  /**
   * @description 添加到场景中去
   * @param { Object3D } scene
   **/
  addTo(scene: Object3D) {
    this.scene = scene;
    this.scene.add(this.object);
  }
  hide() {
    this.object.visible = false;
  }
  show() {
    this.object.visible = true;
  }
}
